package logic;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Collection;
import java.util.Vector;
import logic.gridSimInterface.SimTags;
import logic.schedulers.AbstractGlobalScheduling;
import logic.schedulers.AbstractSchedulerOptimization;
import logic.schedulers.AlgorithmCollection;
import logic.schedulers.AlgorithmPlugin;

/**
 * Trieda, ktora obsahuje informacie o parametroch simulacie:
 * <ul>
 *  <li>nakladovej funkcii
 *  <li>type planovania - staticke, dynamicke
 *  <li>meno globalneho brokera
 *  <li>vybrany algoritmus lokalnej optimalizacie rozvrhu
 *  <li>vybrany algoritmus globalneho pridelovania uloh zdrojom.
 * </ul>
 */
public class SimulationParameters {
    /**
     * Identifikator nakladovej funkcie
     */
    private static int costFunction = SimTags.COST_BY_FINISH_TIME;

    /**
     * Typ planovania - staticke, dynamicke
     */
    private static int planningType = SimTags.DYNAMIC_PLANNING;

    /**
     * meno globalneho brokera
     */
    private static String globalBroker;

    /**
     * planovacie algoritmy
     */
    private static AbstractSchedulerOptimization localScheduler;
    private static AbstractGlobalScheduling globalScheduler;
    
    public static int getCostFunction() {
        return costFunction;
    }

    public static void setCostFunction(int val) {
        costFunction = val;
    }

    public static int getPlanningType() {
        return planningType;
    }

    public static void setPlanningType(int val) {
        planningType = val;
    }

    public static AbstractSchedulerOptimization getLocalScheduler() {
        return localScheduler;
    }

    public static void setLocalScheduler(AbstractSchedulerOptimization aLocalScheduler) {
        localScheduler = aLocalScheduler;
    }

    public static AbstractGlobalScheduling getGlobalScheduler() {
        return globalScheduler;
    }

    public static void setGlobalScheduler(AbstractGlobalScheduling aGlobalScheduler) {
        globalScheduler = aGlobalScheduler;
    }
    
    /**
     * Nacitanie informacii o plugine pre planovanie. Nacita sa
     * nazov algoritmu a potom pomocou triedy AlgorithmCollection
     * sa natiahne aj samotny algoritmus a nastavia sa mu nacitane
     * parametre.
     */
    private static AlgorithmPlugin readAlgorithm(BufferedReader input) throws IOException {
        AlgorithmPlugin result = null;
        String riadok = null;
        
        riadok = input.readLine();
        result = (AlgorithmPlugin) AlgorithmCollection.loadAlgorithm(riadok);
        Collection<String> params = result.getParametersText();
        if (params != null) {
            Vector<String> newValues = new Vector<String>(params.size());
            for (int i = 0; i < params.size(); i++) {
                riadok = input.readLine();
                newValues.add(riadok);
            }
            result.setParametersText(newValues);
        }
        return result;
    }
    
    /**
     * Nacitanie parametrov simulacie zo suboru.
     * @param fileName      nazov existujuceho suboru,
     *                      ktory obsahuje ulozene parametre simulacie
     */
    public static void loadFromFile(String fileName) throws FileNotFoundException {
        File inputFile = new File(fileName);
        //TODO: osetrovacky
        BufferedReader input = new BufferedReader(new FileReader(inputFile));
        
        try {
            String riadok;
            
            riadok = input.readLine();
            costFunction = Integer.parseInt(riadok);
            
            riadok = input.readLine();
            planningType = Integer.parseInt(riadok);
            
            localScheduler = (AbstractSchedulerOptimization) readAlgorithm(input);
            globalScheduler = (AbstractGlobalScheduling) readAlgorithm(input);
            
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    
    /**
     * Vlozenie informacii o algoritme do StringBuffer-u.
     * @param ap    Plugin, ktoreho informacie sa maju ulozit
     * @param obsah Buffer, do ktoreho sa vpisu potrebne informacie,
     *              aby bolo mozne algoritmus znova nacitat.
     */
    private static void appendAlgorithm(AlgorithmPlugin ap, StringBuffer obsah) {
        String koniecRiadku = System.getProperty("line.separator");

        obsah.append(ap.getClass().getCanonicalName());
        obsah.append(koniecRiadku);
        Collection<String> localParams = ap.getParametersText();
        if (localParams != null) {
            for (String elem : localParams) {
                obsah.append(elem);
                obsah.append(koniecRiadku);
            }
        }
    } 
    
	/**
	 * Ulozenie informacii o parametroch simulacie do suboru tak,
	 * aby bolo mozne ich znova nacitat (najma v podprocesoch samotnej
	 * simulacie).
	 * @param	fileName	meno existujuceho suboru
	 */
    public static void saveToFile(String fileName) throws IOException {
        StringBuffer obsah = new StringBuffer();
        String koniecRiadku = System.getProperty("line.separator");
        obsah.append(costFunction);
        obsah.append(koniecRiadku);

        obsah.append(planningType);
        obsah.append(koniecRiadku);
        
        appendAlgorithm(localScheduler, obsah);
        
        appendAlgorithm(globalScheduler, obsah);
        
        File file = new File(fileName);
        //TODO: osetrovacky
        
        Writer output = null;
        try {
            output = new BufferedWriter(new FileWriter(file));
            output.write(obsah.toString());
        } finally {
            if (output != null)
                output.close();
        }
        
    }
}
